package com.coderside.fragment.socket.nio;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.charset.Charset;
import java.util.Iterator;

public class NioServer implements Runnable {
	private Charset charset = Charset.forName("UTF-8");
	private int port = 9999;
	private Selector selector;
	private ServerSocketChannel serverChannel;
	private SocketChannel socketChannel;
	private ByteBuffer readBuffer = ByteBuffer.allocate(8192);

	public NioServer() {
		initSelector();
	}

	public void run() {
		while (true) {
			try {
				this.selector.select();
				Iterator<SelectionKey> selectedKeys = this.selector.selectedKeys().iterator();
				while (selectedKeys.hasNext()) {
					SelectionKey key = (SelectionKey) selectedKeys.next();
					selectedKeys.remove();
					if (!key.isValid()) {
						continue;
					}
					if (key.isAcceptable()) {
						this.accept(key);
					} else if (key.isReadable()) {
						this.read(key);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public void accept(SelectionKey key) throws IOException {
		ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
		if (serverSocketChannel.equals(serverChannel)) {
			socketChannel = serverSocketChannel.accept();
			socketChannel.configureBlocking(false);
			socketChannel.register(this.selector, SelectionKey.OP_READ);
		}
	}

	public void read(SelectionKey key) throws IOException {
		SocketChannel socketChannel = (SocketChannel) key.channel();

		this.readBuffer.clear();

		// Attempt to read off the channel
		int numRead;
		try {
			numRead = socketChannel.read(this.readBuffer);

		} catch (IOException e) {
			// The remote forcibly closed the connection, cancel
			// the selection key and close the channel.
			key.cancel();
			socketChannel.close();
			return;
		}
		if (numRead == -1) {
			// Remote entity shut the socket down cleanly. Do the
			// same from our end and cancel the channel.
			key.channel().close();
			key.cancel();
			return;
		}

		try {
			int mimeType = readBuffer.get();
			if (mimeType == 0) {
				String input = new String(readBuffer.array()).trim();
				System.out.println(input);
			} else if (mimeType == 1) {
				FileOutputStream fos = new FileOutputStream(new File("zz22.zip"));
				fos.write(readBuffer.array());
				fos.close();
			}

		} catch (IOException e) {
			//				e.printStackTrace();
		}

		String input = new String(readBuffer.array()).trim();
		System.out.println(input);
		//===========以上是读取用户请求命令====================

		//===========以下是返回给请求用户的数据====================
		readBuffer.clear();
		byte inBuffer[] = new byte[100];
		System.out.println("请输入命令：");
		System.in.read(inBuffer);
		readBuffer.put(inBuffer);
		readBuffer.flip();
		socketChannel.write(readBuffer);
	}

	/**
	 * 注册事件到selector；
	 */
	public void initSelector() {
		try {
			selector = SelectorProvider.provider().openSelector();
			this.serverChannel = ServerSocketChannel.open();
			serverChannel.configureBlocking(false);
			InetSocketAddress isa = new InetSocketAddress("localhost", this.port);
			serverChannel.socket().bind(isa);
			serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		NioServer server = new NioServer();
		Thread t = new Thread(server);
		t.start();
	}

}
